#include "menu.h"

CMenu::CMenu(float x, float y):
    m_nSelected(0),
    m_fX(x),
    m_fY(y),
    m_bActive(false),

    // The child class is the title if we have one
    CUIText("", "bomberman")
{
    setMarginLeft(x);
    setMarginTop(y);
}

CMenu::~CMenu()
{
    if (m_arrOptions.size() > 0)
    {
        for (vector<COption*>::const_iterator pPos(m_arrOptions.begin());
             pPos != m_arrOptions.end(); ++pPos)
        {
            delete *pPos;
        }
        m_arrOptions.clear();
    }
}

COption* CMenu::addOption(string szText, int nLeft, int nTop)
{
    COption* pOption = new COption(m_arrOptions.size(), szText);
    pOption->setPosition(static_cast<float>(nLeft) + m_fX, 
        static_cast<float>(nTop) + m_fY, 0, 0);

    m_arrOptions.push_back(pOption);

    if (getOptionCount() == 1)
    {
        pOption->setActive(true);
    }

    return pOption;
}

void CMenu::removeOption(int index)
{
    vector<COption*>::iterator it = m_arrOptions.begin();
    advance(it, index);
    delete *it;
    m_arrOptions.erase(it);
}

COption* CMenu::getOption(int index) const
{
    return (m_arrOptions.at(index));
}

size_t CMenu::getOptionCount() const
{
    return m_arrOptions.size();
}

void CMenu::incrementSelection()
{
    int nOldSelect(m_nSelected);
    getOption(m_nSelected)->setActive(false);
    if (m_nSelected < getOptionCount() - 1)
    {
        ++m_nSelected;
    }
    else
    {
        m_nSelected = 0;
    }

    // Call the on change event
    onChange(getOption(nOldSelect), getOption(m_nSelected));

    getOption(m_nSelected)->setActive(true);
    FMOD::Channel *pChannel(nullptr);
    CSoundManager::getInstance()->getSound(
        "change_selection.wav")->createNewChannel(&pChannel);
    pChannel->setPaused(false);
}

void CMenu::decrementSelection()
{
    int nOldSelect(m_nSelected);
    getOption(m_nSelected)->setActive(false);
    if (m_nSelected > 0)
    {
        --m_nSelected;
    }
    else
    {
        m_nSelected = getOptionCount() - 1;
    }

    // Call the on change event
    onChange(getOption(nOldSelect), getOption(m_nSelected));

    getOption(m_nSelected)->setActive(true);
    FMOD::Channel *pChannel(nullptr);
    CSoundManager::getInstance()->getSound(
        "change_selection.wav")->createNewChannel(&pChannel);
    pChannel->setPaused(false);
}

bool CMenu::isActive() const
{
    return m_bActive;
}

void CMenu::setActiveColour(float red, float green, float blue, float alpha)
{
    for (vector<COption*>::const_iterator pOption(m_arrOptions.begin());
            pOption != m_arrOptions.end(); ++pOption)
    {
        (*pOption)->setActiveColour(red, green, blue, alpha);
    }
}

void CMenu::setInactiveColour(float red, float green, float blue, float alpha)
{
    for (vector<COption*>::const_iterator pOption(m_arrOptions.begin());
            pOption != m_arrOptions.end(); ++pOption)
    {
        (*pOption)->setInactiveColour(red, green, blue, alpha);
    }
}

void CMenu::setActive(bool bActive)
{
    if (bActive)
    {
        onActivate();
    }
    else
    {
        onDeactivate();
    }
    m_bActive = bActive;
}

void CMenu::handleInput(const DEVICE_EVENT &evt)
{
    if (isActive())
    {
        if (evt.type == DEVICE_KEYBOARD)
        {
            CKeyboard *pKeyboard(dynamic_cast<CKeyboard*>(evt.pDevice));
            if (pKeyboard->keyPressed(evt.charrKeyboardData, DIK_DOWN))
            {
                pKeyboard->registerKeyDebounce(DIK_DOWN, CTimer() + 200.0f);
                incrementSelection();
            }
            else if (pKeyboard->keyPressed(evt.charrKeyboardData, DIK_UP))
            {
                pKeyboard->registerKeyDebounce(DIK_UP, CTimer() + 200.0f);
                decrementSelection();
            }

            else if (pKeyboard->keyPressed(evt.charrKeyboardData, 
                DIK_NUMPADENTER))
            {
                pKeyboard->registerKeyDebounce(DIK_NUMPADENTER, 
                    CTimer() + 200.0);
                callSelected(DIK_NUMPADENTER);
            }
            
            else if (pKeyboard->keyPressed(evt.charrKeyboardData, DIK_RETURN))
            {
                pKeyboard->registerKeyDebounce(DIK_RETURN, CTimer() + 200.0);
                callSelected(DIK_RETURN);
            }

            else if (pKeyboard->keyPressed(evt.charrKeyboardData, DIK_LEFT))
            {
                pKeyboard->registerKeyDebounce(DIK_LEFT, CTimer() + 200.0);
                callSelected(DIK_LEFT);
            }
                
            else if (pKeyboard->keyPressed(evt.charrKeyboardData, DIK_RIGHT))
            {
                pKeyboard->registerKeyDebounce(DIK_RIGHT, CTimer() + 200.0);
                callSelected(DIK_RIGHT);
            }
        }
    }
}

void CMenu::callSelected(unsigned char chKey)
{
    getOption(m_nSelected)->callFunction(this, chKey);
    onSelected(getOption(m_nSelected));

    FMOD::Channel *pChannel(nullptr);
    CSoundManager::getInstance()->getSound(
        "select.wav")->createNewChannel(&pChannel);
    pChannel->setPaused(false);
}

void CMenu::render()
{
    if (isActive())
    {
        for (vector<COption*>::const_iterator pOption(m_arrOptions.begin());
             pOption != m_arrOptions.end(); ++pOption)
        {
            (*pOption)->render();
        }
        CUIText::render();
    }
}

int CMenu::getCurrentSelectionIndex() const
{
    return m_nSelected;
}

COption *CMenu::getCurrentOption() const
{
    return getOption(m_nSelected);
}

void CMenu::setTitle(const string &szTitle, float fXOffset, float fYOffset)
{
    setMarginLeft(m_fX + fXOffset);
    setMarginTop(m_fY + fYOffset);
    setText(szTitle);
}

string CMenu::getTitle() const
{
    return getText();
}

float CMenu::getLeft() const
{
    return m_fX;
}

float CMenu::getTop() const
{
    return m_fY;
}